import { defaults } from "lodash";
import { cellDeault, offsetCheckLeft, offsetCheckTop } from "../config";
import { CellInfo, CellOption, ColumnList, Rect, RowList } from "../types";
import { calcTitle } from "./calcBox";
import { lineHorizontal, lineVertical, brush, text } from "./drawTools";

// 鼠标当前所在单元格相对于起始点击单元格位置
type endCellPosition = "Left-Top" | "Left-Bottom" | "Right-Top" | "Right-Bottom"
export type InputCellInfo = { x: number; y: number; ex: number; ey: number; info: { xi: number; yi: number, text: string; }; }

type ChooseCell = {
  startCell?: InputCellInfo | null;
  endCell?: InputCellInfo | null;
  mixCell?: { x: number; y: number; ex: number; ey: number; } | null;
  endCellPosition?: endCellPosition
}

export interface ExcelInterface {
  readonly dom: HTMLCanvasElement;
  readonly ctx: CanvasRenderingContext2D;
  readonly transformX: number;
  readonly transformY: number;
  readonly rect: Rect;
  readonly x2yCellInfo: { [key in number]: { [key in number]: CellInfo } };
  readonly y2xCellInfo: { [key in number]: { [key in number]: CellInfo } };
  transform: (x: number, y: number) => ExcelInterface;
  /* 获取选中单元格信息 */
  getCell: (obj: { x: number; y: number; }) => InputCellInfo | null;
  /* 点击框选单元格 */
  getCellStart: (obj: { x: number; y: number; }) => InputCellInfo | null;
  /* 松开点击获取所有单元格 */
  getCellEnd: (obj: { x: number; y: number; }) => ChooseCell;
  /* 渲染 */
  render: () => void;
  /* 文本写入单元格 */
  renderSingleCellText: (xi: number, yi: number, str: string) => void
}

class ExcelRender implements ExcelInterface {
  dom
  ctx
  // 绘制区域参数信息
  rect: Rect
  constructor(dom: HTMLCanvasElement, rect: Rect) {
    this.dom = dom;
    dom.width = rect.width || 0
    dom.height = rect.height || 0
    this.ctx = dom.getContext("2d") as CanvasRenderingContext2D
    // 初始化一些过程数据
    this.rect = rect
    this.addBorderPosition(rect.width + offsetCheckLeft, 'x')
    this.addBorderPosition(rect.height + offsetCheckTop, 'y')
    this.calcBoxIndex(0, 0, rect.width, rect.height)
    // 初始化标题单元格数据
    this.addTitleCellInfo()
  }

  // 存储全量行列累加宽高
  private columnList: ColumnList = []
  private rowList: RowList = []
  // 新创建的
  private newRowList: RowList = []
  private newColumnList: ColumnList = []
  private lastBorderLeftEnd: number = 0
  private lastBorderTopEnd: number = 0
  // 计算新增存储边框逻辑
  private addBorderPosition(end: number, direction: "x" | "y") {
    if (direction === "x") {
      const bl = this.lastBorderLeftEnd
      const cellWidth = cellDeault.width
      const halfCellWidth = cellWidth / 2
      const pl = cellDeault.paddingLeft
      const pr = cellDeault.paddingRight
      if (end > bl) {
        this.newColumnList = Array(Math.ceil((end - bl) / cellWidth)).fill(0).map((_, i) => {
          const cellLeft = i * cellDeault.width + bl
          const cellRight = cellLeft + cellWidth
          return {
            cellLeft,
            offsetCellLeft: cellLeft + offsetCheckLeft,
            cellRight,
            left: cellLeft + pl,
            right: cellRight - pr,
            center: cellLeft + halfCellWidth,
            width: cellWidth
          }
        })
        this.columnList.push(...this.newColumnList)
        this.lastBorderLeftEnd = this.columnList[this.columnList.length - 1].cellRight
      }
    } else if (direction === "y") {
      const cellHeight = cellDeault.height
      const halfCellHeight = cellHeight / 2
      const bt = this.lastBorderTopEnd
      const halfFZ = cellDeault.fontSize / 2
      if (end > bt) {
        this.newRowList = Array(Math.ceil((end - bt) / cellDeault.height)).fill(0).map((_, i) => {
          const cellTop = i * cellDeault.height + bt
          return {
            cellTop,
            offsetCellTop: cellTop + offsetCheckTop,
            cellBottom: cellTop + cellHeight,
            center: cellTop + halfCellHeight + halfFZ,
            height: cellHeight
          }
        })
        this.rowList.push(...this.newRowList)
        this.lastBorderTopEnd = this.rowList[this.rowList.length - 1].cellBottom
      }
    }
  }

  // 可视区第一个一个索引
  private vxIndexStart = 0;
  private vxIndexEnd = 0;
  private vyIndexStart = 0;
  private vyIndexEnd = 0;
  // 计算可视区第一个索引
  private calcBoxIndex(startX: number, startY: number, endX: number, endY: number): void {
    this.vxIndexStart = this.columnList.findIndex(e => e.offsetCellLeft >= startX)
    this.vxIndexEnd = this.columnList.findIndex(e => e.offsetCellLeft >= endX)
    this.vyIndexStart = this.rowList.findIndex(e => e.offsetCellTop >= startY)
    this.vyIndexEnd = this.rowList.findIndex(e => e.offsetCellTop >= endY)
  }

  private drawBorder() {
    brush(this.ctx)
    const vxe = this.vxIndexEnd
    const vye = this.vyIndexEnd
    const width = this.rect.width
    const height = this.rect.height
    for (let index = this.vxIndexStart; index <= vxe; index++) {
      const obj = this.columnList[index]
      lineVertical(this.ctx, obj.cellLeft, this.transformY, height)
    }
    for (let index = this.vyIndexStart; index <= vye; index++) {
      const obj = this.rowList[index]
      lineHorizontal(this.ctx, this.transformX, obj.cellTop, width)
    }
  }
  // 单元格信息缓存
  x2yCellInfo: { [key: number]: { [key: number]: CellInfo } } = {}
  y2xCellInfo: { [key: number]: { [key: number]: CellInfo } } = {}
  // 单元格有信息的x/y轴
  private xWithCellInfo: number[] = []
  private yWithCellInfo: number[] = []
  // 获取单元格默认配置（默认使用单元格初始化后的默认配置）
  private setCellConfig(x: number, y: number, text: string, cellOption: Partial<CellOption> = {}) {
    // 单元格信息
    if (!this.x2yCellInfo[x]) this.x2yCellInfo[x] = {}
    if (!this.y2xCellInfo[y]) this.y2xCellInfo[y] = {}
    const obj = this.y2xCellInfo[y][x] = this.x2yCellInfo[x][y] = defaults<{ x: number; y: number; text: string }, Partial<CellOption>, CellOption>({
      x,
      y,
      text
    }, cellOption, cellDeault)
    this.xWithCellInfo = Object.keys(this.x2yCellInfo).map(Number)
    this.yWithCellInfo = Object.keys(this.y2xCellInfo).map(Number)
    return obj
  }

  // 添加默认第一行和第一列单元格信息
  addTitleCellInfo() {
    // 水平划线，填的是第一列的值
    const rowStart = this.rowList.length - this.newRowList.length
    this.newRowList.forEach((_, index) => {
      this.setCellConfig(0, index + rowStart, index + rowStart + "", { textAlign: "center" })
    })
    // 垂直划线，填的是第一行的值
    const columnStart = this.columnList.length - this.newColumnList.length
    this.newColumnList.forEach((_, index) => {
      this.setCellConfig(index + columnStart, 0, calcTitle(index + columnStart), { textAlign: "center" })
    })
  }
  // 绘制默认表格内容
  private drawText() {
    const ctx = this.ctx
    // 开始位置索引
    const vxStart = this.vxIndexStart
    const vyStart = this.vyIndexStart
    // 结束位置索引
    const vxEnd = this.vxIndexEnd
    const vyEnd = this.vyIndexEnd
    // 找出需要绘制内容的索引列表
    const xs = this.xWithCellInfo.filter(x => x >= vxStart && x <= vxEnd)
    const ys = this.yWithCellInfo.filter(y => y >= vyStart && y <= vyEnd)
    if (xs > ys) {
      xs.forEach(x => {
        ys.forEach(y => {
          const ci = this.x2yCellInfo[x][y]
          if (ci) {
            text(ctx, ci, this.columnList[x][ci.textAlign], this.rowList[y].center)
          }
        })
      })
    } else {
      ys.forEach(y => {
        xs.forEach(x => {
          const ci = this.x2yCellInfo[x][y]
          if (ci) {
            text(ctx, ci, this.columnList[x][ci.textAlign], this.rowList[y].center)
          }
        })
      })
    }
    return this
  }

  getCell({ x, y }: { x: number; y: number; }) {
    const cxi = this.columnList.findIndex(e => e.offsetCellLeft >= x)
    const cyi = this.rowList.findIndex(e => e.offsetCellTop >= y)
    if (cxi !== -1 && cyi !== -1) {
      const cx = this.columnList[cxi]
      const cy = this.rowList[cyi]
      return {
        x: cx.cellLeft,
        y: cy.cellTop,
        ex: cx.cellRight,
        ey: cy.cellBottom,
        info: {
          xi: cxi,
          yi: cyi,
          text: this.x2yCellInfo[cxi]?.[cyi]?.text || ""
        }
      }
    }
    return null
  }

  private cacheCell: InputCellInfo | null = null
  getCellStart(obj: { x: number; y: number; }) {
    this.cacheCell = this.getCell(obj)
    return this.cacheCell
  }
  getCellEnd(obj: { x: number; y: number; }) {
    const startCell = this.cacheCell
    const endCell = this.getCell(obj)
    let endCellPosition
    const ret: ChooseCell = {
      startCell,
      endCell,
    }
    if (endCell && startCell) {
      if (startCell.x > endCell.x) {
        endCellPosition = "Left-"
        ret.mixCell = {
          x: endCell.x,
          ex: startCell.ex,
          y: 0,
          ey: 0
        }
      } else {
        endCellPosition = "Right-"
        ret.mixCell = {
          x: startCell.x,
          ex: endCell.ex,
          y: 0,
          ey: 0
        }
      }
      if (startCell.y > endCell.y) {
        endCellPosition += "Top"
        ret.mixCell.y = endCell.y
        ret.mixCell.ey = startCell.ey
      } else {
        endCellPosition += "Bottom"
        ret.mixCell.y = startCell.y
        ret.mixCell.ey = endCell.ey
      }
      ret.endCellPosition = endCellPosition as endCellPosition
    }
    return ret
  }

  // 修改行列宽高，存储不同宽高的行列
  // resize(index: number, size: number, direction: "x" | "y") {
  //   if (direction === 'x') {
  //     this.resizeX[index] = { width: size }
  //     const s = size - cellDeault.width
  //     this.borderLeftStart = this.columnList.map((e, i) => i < index ? e : e + s * i)
  //   } else if (direction === "y") {
  //     this.resizeY[index] = { height: size }
  //     const s = size - cellDeault.height
  //     this.borderTopStart = this.borderTopStart.map((e, i) => i < index ? e : e + s * i)
  //   }
  //   return this
  // }

  // 已经滚动的位置
  transformX = 0
  transformY = 0
  // 滚动表格（重新计算可视区域）
  transform(x: number, y: number) {
    this.ctx.transform(1, 0, 0, 1, this.transformX - x, this.transformY - y)
    this.transformX = x
    this.transformY = y
    // 关于边框的运算
    const endX = x + this.rect.width + offsetCheckLeft
    const endY = y + this.rect.height + offsetCheckTop
    this.addBorderPosition(endX, 'x')
    this.addBorderPosition(endY, 'y')
    this.calcBoxIndex(x, y, endX, endY)
    // 关于单元格文本的运算
    this.addTitleCellInfo()
    return this
  }

  render() {
    // 清空绘制区域
    this.ctx.clearRect(this.transformX, this.transformY, this.rect.width + this.transformX, this.rect.height + this.transformY);
    // 绘制
    this.drawBorder()
    this.drawText()
    return this
  }

  // 渲染单个单元格内容
  renderSingleCellText(xi: number, yi: number, str: string) {
    const obj = this.x2yCellInfo?.[xi]?.[yi]
    const col = this.columnList[xi]
    const row = this.rowList[yi]
    if (obj) {
      console.log(xi, yi, row, col);
      obj.text = str
      this.ctx.clearRect(col.cellLeft + 1, row.cellTop + 1, col.width - 1, row.height - 1)
      text(this.ctx, obj, col[obj.textAlign], row.center)
    } else {
      const obj = this.setCellConfig(xi, yi, str, { textAlign: "right" })
      this.ctx.clearRect(col.cellLeft + 1, row.cellTop + 1, col.width - 1, row.height - 1)
      text(this.ctx, obj, col[obj.textAlign], row.center)
    }
  }
}

function Exl(dom: HTMLCanvasElement, rect: Rect): ExcelInterface {
  const er = new ExcelRender(dom, rect)
  return er
}

export default Exl